/*
 * Copyright 2011 www.pretty-tools.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "stdafx.h"
#include "FileOutputStream.h"

#define NS_SEEK_SET  	0
#define NS_SEEK_CUR 	1
#define NS_SEEK_END 	2

#define PR_RDONLY       0x01
#define PR_WRONLY       0x02
#define PR_RDWR         0x04
#define PR_CREATE_FILE  0x08
#define PR_APPEND       0x10
#define PR_TRUNCATE     0x20
#define PR_SYNC         0x40
#define PR_EXCL         0x80

// CFileOutputStream

CFileOutputStream::CFileOutputStream()
{
    ATLTRACE( _T("CFileOutputStream::CFileOutputStream()\n") );
}

CFileOutputStream::~CFileOutputStream()
{
    ATLTRACE( _T("CFileOutputStream::~CFileOutputStream()\n") );
}

STDMETHODIMP CFileOutputStream::init(ILocalFile* file, LONG ioFlags, LONG perm, LONG behaviorFlags)
{
    if (!file)
        return E_INVALIDARG;

    VARIANT_BOOL vbSafe = VARIANT_FALSE;
    RETURN_FAILED(file->GetSafe(&vbSafe))

    CComBSTR bsPath;
    RETURN_FAILED(file->get_nativePath(&bsPath))

    RETURN_FAILED(Init(bsPath, vbSafe));

    ATLASSERT(!ioFlags || (ioFlags & (PR_WRONLY|PR_CREATE_FILE|PR_APPEND|PR_TRUNCATE)));
    ATLASSERT(!perm);
    ATLASSERT(!behaviorFlags);

    DWORD dwCreationDisposition = 0;

    if (ioFlags & PR_CREATE_FILE)
    {
        if (ioFlags & PR_APPEND)
            dwCreationDisposition |= OPEN_ALWAYS;
        else
            dwCreationDisposition |= CREATE_ALWAYS;
    }
    else
    {
        if (ioFlags & PR_APPEND)
            dwCreationDisposition |= OPEN_EXISTING;
        else
            dwCreationDisposition |= TRUNCATE_EXISTING;
    }

    RETURN_E_FAIL_ON_FALSE(m_file.Create(m_strPath, GENERIC_WRITE, 0, dwCreationDisposition));

    if (ioFlags & PR_APPEND)
        return seek(NS_SEEK_END, 0);

    return S_OK;
}

STDMETHODIMP CFileOutputStream::finish(void)
{
    return close();
}

STDMETHODIMP CFileOutputStream::close(void)
{
    m_file.Close();

    return S_OK;
}

STDMETHODIMP CFileOutputStream::flush(void)
{
    return S_OK;
}

STDMETHODIMP CFileOutputStream::seek(LONG whence, LONGLONG offset)
{
    LARGE_INTEGER liOffset;
    liOffset.QuadPart = offset;
    RETURN_HRESULT(m_file.SetPointer(liOffset, whence));
}

STDMETHODIMP CFileOutputStream::tell(ULONGLONG* pRet)
{
    if (!pRet)
        return E_POINTER;

    LARGE_INTEGER liPos = {0,0};
    RETURN_E_FAIL_ON_FALSE(m_file.GetPosition(&liPos))

    *pRet = liPos.QuadPart;

    return S_OK;
}

STDMETHODIMP CFileOutputStream::write(BSTR data, LONG count, LONG* pRet)
{
    if (!data || !count || ((UINT)count) > SysStringLen(data))
        return E_INVALIDARG;
    if (!pRet)
        return E_POINTER;
    if (!m_file)
        return E_UNEXPECTED;

	CStringA strResult;

    int nCnt = AtlUnicodeToUTF8(data, count, NULL, 0);
	if (nCnt != 0)
	{
		nCnt = AtlUnicodeToUTF8(data, count, strResult.GetBuffer(nCnt), nCnt+1);
		strResult.ReleaseBuffer(nCnt);
	}

    if (!m_file.Write((LPCSTR)strResult, strResult.GetLength()))
        return E_FAIL;

    *pRet = m_file.GetNumberOfBytesWrite();

    return S_OK;
}

STDMETHODIMP CFileOutputStream::setEOF()
{
    return E_NOTIMPL;
}

STDMETHODIMP CFileOutputStream::isNonBlocking(VARIANT_BOOL* pRet)
{
    return E_NOTIMPL;
}
